<template>
  <div class="app-container">
    <el-card v-loading="loading">
      <Treetools :item="header" :is-header="true" @show-dailog="showDialog" />
      <!-- 1.树形结构 -->
      <!--1.1.tree组件上的props字段 用于指定渲染树形组件文字的数组中的字段
          label用于指定树形组件左侧的文字在那个字段渲染;children 用于指定树形组件的子节点取用那个字段
          1.2.引入树形组件 绑定数据和props字段;树形组件支持自定义子节点;在树形组件中的作用域插槽插入dom元素可以
          实现自定义树形组件的子节点;作用域插槽的写法#default="{data}"解构出来的数据-->
      <el-tree :data="list" :props="defaultProps">
        <template #default="{ data }">
          <Treetools :item="data" @show-dailog="showDialog" @del="delFn" />
        </template>
      </el-tree>
      <!-- 添加子部门的弹出层
        :close-on-click-modal="true"点击弹出层之外就会关闭-->
      <el-dialog
        :title="title"
        :visible="dialogVisible"
        :close-on-click-modal="true"
        width="40%"
        @close="closeDialog"
        @open="openDialog"
      >
        <!-- 表单 -->
        <el-form
          ref="departRef"
          :model="departForm"
          :rules="departRules"
          label-width="120px"
        >
          <el-form-item label="部门名称" prop="name">
            <el-input
              v-model="departForm.name"
              style="width: 80%"
              placeholder="1-50个字符"
            />
          </el-form-item>
          <el-form-item label="部门编码" prop="code">
            <el-input
              v-model="departForm.code"
              style="width: 80%"
              placeholder="1-50个字符"
            />
          </el-form-item>
          <el-form-item label="部门负责人" prop="manager">
            <el-select
              v-model="departForm.manager"
              style="width: 80%"
              placeholder="请选择"
            >
              <el-option
                v-for="item in managerList"
                :key="item.id"
                :label="item.username"
                :value="item.username"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="部门介绍" prop="introduce">
            <el-input
              v-model="departForm.introduce"
              style="width: 80%"
              placeholder="1-300个字符"
              type="textarea"
            />
          </el-form-item>
        </el-form>
        <!-- 底部内容 -->
        <span slot="footer" class="dialog-footer">
          <el-button @click="closeDialog">取 消</el-button>
          <el-button type="primary" @click="submit">确 定</el-button>
        </span>
      </el-dialog>
    </el-card>
  </div>
</template>

<script>
import { getManagerList } from '@/api/employee'
import { getDepartment, addDepartment, getDepartDetail, updateDepartDetail, delDepartDetail } from '@/api/department'
import Treetools from './components/tree-tools.vue'
import transTree from '@/utils/transTree'
export default {
  components: {
    Treetools
  },
  data() {
    // 自定义校验部门编码--添加的部门不能与之前数据的编码不能重复
    // value--就是绑定自定义校验输入框的值--如果不符合就是提示用户；符合直接通过放行
    // 编辑的编号校验允许和自己的编号一致所以不能使用新增部门的校验规则
    const validateCode = (rule, value, callback) => {
      // 编辑校验
      if (this.departForm.id && value === this.departForm.code) {
        callback()
        return
      }
      // 新增校验
      const isSame = this.originList.some(item => item.code === value)
      isSame ? callback(new Error('部门编码已存在')) : callback()
    }
    // 自定义校验部门名称
    // 编辑部门的名字不能和自己所在的节点的兄弟同名--如果输入名字饿自己选择一致直接通过
    // 否则需要通过pid找到和自己pid一样的就是自己的兄弟
    const validateName = (rule, value, callback) => {
      let borArr = []
      if (this.departForm.id) { // 编辑部门校验
        if (this.currentNode.name === value) {
          return callback()
        } else {
          borArr = this.originList.filter(item => item.pid === this.currentNode.pid)
        }
      } else { // 新增部门校验
        borArr = this.originList.filter(item => item.pid === this.currentNode.id)
      }

      const isSame = borArr.some(item => item.name === value)
      isSame ? callback(new Error('部门名称已存在')) : callback()
    }
    return {
      loading: false,
      dialogVisible: false, // 控制弹出层
      list: [],
      originList: [], // 扁平化数据-原始数据
      header: {},
      currentNode: {}, // 通过子组件触发拿到点击节点
      managerList: [], // 获取下拉列表数据
      departForm: { // 表单数据
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '' // 部门介绍
      },
      departRules: { // 表单校验规则
        name: [
          { required: true, message: '部门名称不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 50, message: '部门名称要求1-50个字符', trigger: ['blur', 'change'] },
          { validator: validateName, trigger: ['blur', 'change'] }
        ],
        code: [
          { required: true, message: '部门编码不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 50, message: '部门编码要求1-50个字符', trigger: ['blur', 'change'] },
          { validator: validateCode, trigger: ['blur', 'change'] }
        ],
        manager: [
          { required: true, message: '部门负责人不能为空', trigger: ['blur', 'change'] }
        ],
        introduce: [
          { required: true, message: '部门介绍不能为空', trigger: ['blur', 'change'] },
          { min: 1, max: 300, message: '部门介绍要求1-300个字符', trigger: ['blur', 'change'] }
        ]
      },
      defaultProps: {
        children: 'children',
        label: 'name'
      }
    }
  },
  // 利用表单控制标题可以利用计算属性--return
  computed: {
    title() {
      return this.departForm.id ? '编辑部门' : '新增部门'
    }
  },
  created() {
    this.getDepartment()
  },
  methods: {
    // 获取树形数据
    async getDepartment() {
      this.loading = true
      try {
        const res = await getDepartment()
        // 需要在头部加一个id=''因为公司需要匹配部门的父亲这样不可以和部门重名
        this.header = { name: res.data.companyName, manager: '负责人', id: '' }
        this.list = transTree(res.data.depts)
        this.originList = res.data.depts
        this.loading = false
      } catch (err) {
        this.loading = false
        console.log(err)
      }
    },
    // 获取编辑部门的接口数据--这里是一个形参不能直接那到当前点击项id
    // --因为需要找到编辑才能得到点击对应项的数据
    async getDepartDetail(id) {
      const { data } = await getDepartDetail(id)
      this.departForm = data
    },
    // 点击添加节点显示弹出层&拿到对应行的数据--需要拿到当前节点判断新增的部门名称
    // -不能与父亲的子节点名称重复，首先需要把点击节点的子节点找出来再去判断新增名字是否相同
    // 添加--编辑和添加共用一个弹出层需要用type来区分一下
    // 调用编辑接口通过id来查询对应的项并且把把得到数据做一个回写
    showDialog(currentNode, type) {
      if (type === 'edit') {
        this.getDepartDetail(currentNode.id)
      }
      this.dialogVisible = true
      this.currentNode = currentNode
    },
    // 在打开弹出层的时候请求接口得到负责人的下列列表的数据
    // 弹出层提供一个open事件--有一个Dialog的回调
    async openDialog() {
      const { data } = await getManagerList()
      this.managerList = data
    },
    // 关闭和取消弹出层回调--需要把输入和校验的表单项情况否则下次打开上一次数据还是存在
    // 表单重置-resetFields 用于将表单的数据重置为初始值并且将表单校验移除
    // resetFields必须配合el-form-item中的prop一起使用
    // 如果数据没有绑定 使用resetFields()清楚不掉 所以针对这些没有绑定的数据就需要手动置空
    closeDialog() {
      this.dialogVisible = false
      this.$refs.departRef.resetFields()
      this.departForm = {
        name: '',
        code: '',
        manager: '',
        introduce: ''
      }
    },
    // 点击弹出层的确定新增部门--调用接口提交
    // 因为需要提交的接口参数--表单数据+一个父级部门ID就是点击当前项id
    // 根据当前表单中是否存在id区分编辑和新增
    // 如果  this.departForm有id就是点击编辑确定按钮否则就是点击新增的确定
    submit() {
      this.$refs.departRef.validate(async(isOk) => {
        if (isOk) {
          if (this.departForm.id) {
            await updateDepartDetail(this.departForm)
          } else {
            await addDepartment({
              ...this.departForm, pid: this.currentNode.id
            })
          }

          this.dialogVisible = false// 关闭弹出层
          this.$message.success(this.title + '成功')
          this.getDepartment()// 重新刷新一下数据
        }
      })
    },
    // 根据id删除数据
    delFn(item) {
      this.$confirm('此操作将永久删除该部门, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async() => {
        // 2. 调用接口
        await delDepartDetail(item.id)
        // 3. 提示用户
        this.$message.success('删除成功')
        // 4. 刷新列表
        this.getDepartment()
      })
    }
  }
}
</script>

<style lang="scss">
.app-container {
  padding: 20px;
}
</style>
